<template>
  <view :class="cascaderClass" :style="cascaderStyle">
    <sar-tabs scrollable v-model:current="tabsCurrent" :list="tabsList" />

    <slot name="top" :tab-index="tabsCurrent"></slot>

    <view :class="bem.e('container')">
      <view
        :class="bem.e('wrapper')"
        :style="
          stringifyStyle({
            transform: `translateX(${-Number(tabsCurrent) * 100}%)`,
            transitionDuration: renderedPane ? null : '0s',
          })
        "
      >
        <view
          v-for="(tab, tabIndex) in tabs"
          :key="tabIndex"
          :class="bem.e('pane')"
        >
          <view :class="bem.e('options')">
            <scroll-view scroll-y trap-scroll :class="bem.e('scroll')">
              <view
                v-for="(option, optionIndex) in tab.options"
                :key="optionIndex"
                :class="
                  classNames(
                    bem.e('option'),
                    bem.em(
                      'option',
                      'selected',
                      tab.selected &&
                        tab.selected[mergedFieldKeys.value] ===
                          option[mergedFieldKeys.value],
                    ),
                    bem.em(
                      'option',
                      'disabled',
                      option[mergedFieldKeys.disabled],
                    ),
                  )
                "
                @click="onOptionClick(option, tabIndex)"
              >
                <view :class="bem.e('option-label')">
                  {{
                    labelRender
                      ? labelRender(option)
                      : option[mergedFieldKeys.label]
                  }}
                </view>
                <view :class="bem.e('option-icon')">
                  <sar-icon family="sari" name="success" />
                </view>
              </view>
            </scroll-view>
            <view
              :class="
                classNames(
                  bem.e('loading-wrapper'),
                  bem.em('loading-wrapper', 'show', tab.options.length === 0),
                )
              "
            >
              <view :class="bem.e('loading')">
                <sar-loading />
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from "vue";
import { computed, ref, watch } from "vue";
import {
  classNames,
  stringifyStyle,
  createBem,
  isEmptyBinding
} from "../../utils";
import { useTranslate } from "../locale";
import SarTabs from "../tabs/tabs.vue";
import SarIcon from "../icon/icon.vue";
import SarLoading from "../loading/loading.vue";
import {
  defaultFieldKeys,
  getSelectedOptionsByValue,
  defaultCascaderProps
} from "./common";
/**
 * @property {string} rootClass 组件根元素类名，默认值：-。
 * @property {StyleValue} rootStyle 组件根元素样式，默认值：-。
 * @property {string | number} modelValue 选中项的值，默认值：-。
 * @property {CascaderOption[]} options 可选项数据源，默认值：[]。
 * @property {CascaderFieldKeys} fieldKeys 自定义 `options` 中的字段，默认值：defaultFieldKeys。
 * @property {string} hintText 未选中时的提示文案，默认值：'请选择'。
 * @property {(option: CascaderOption) => string} labelRender 自定义可选项渲染，默认值：-。
 * @property {boolean} changeOnSelect 点击每级选项都会触发变化，默认值：false。
 * @event {(value: string | number, selectedOptions: CascaderOption[]) => void} update 全部选项选择完成后触发
 * @event {(value: string | number, selectedOptions: CascaderOption[]) => void} change 全部选项选择完成后触发
 * @event {(option: CascaderOption, tabIndex: number) => void} select 选中某一项时触发
 */
export default  _defineComponent({
  components: {
    SarTabs,
    SarIcon,
    SarLoading,
  },
  ...{
    options: {
      virtualHost: true,
      styleIsolation: "shared"
    }
  },
  __name: "cascader",
  props:  _mergeDefaults({
    rootStyle: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
    rootClass: { type: String, required: false },
    modelValue: { type: [String, Number], required: false },
    options: { type: Array, required: false },
    fieldKeys: { type: Object, required: false },
    hintText: { type: String, required: false },
    labelRender: { type: Function, required: false },
    changeOnSelect: { type: Boolean, required: false }
  }, defaultCascaderProps),
  emits: ["update:model-value", "change", "select"],
  setup(__props, { expose: __expose, emit: __emit }) {
    __expose();
    const props = __props;
    const emit = __emit;
    const bem = createBem("cascader");
    const { t } = useTranslate("cascader");
    const updateTabs = () => {
      let nextTabs;
      if (isEmptyBinding(tempValue)) {
        nextTabs = [
          {
            options: props.options || [],
            selected: null
          }
        ];
      } else {
        const selectedOptions = getSelectedOptionsByValue(
          props.options || [],
          tempValue,
          mergedFieldKeys.value
        );
        if (selectedOptions) {
          let nextOptions = props.options;
          nextTabs = selectedOptions.map((option) => {
            const tab = {
              options: nextOptions,
              selected: option
            };
            nextOptions = option[mergedFieldKeys.value.children];
            return tab;
          });
          if (nextOptions) {
            nextTabs.push({
              options: nextOptions,
              selected: null
            });
          }
        } else {
          nextTabs = [
            {
              options: props.options || [],
              selected: null
            }
          ];
        }
      }
      if (nextTabs) {
        tabs.value = nextTabs;
        tabsCurrent.value = nextTabs.length - 1;
        if (!renderedPane.value) {
          setTimeout(() => {
            renderedPane.value = true;
          }, 30);
        }
      }
    };
    const isLastOption = (option) => {
      return !Array.isArray(option[mergedFieldKeys.value.children]);
    };
    const onOptionClick = (option, tabIndex) => {
      if (option.disabled) {
        return;
      }
      let nextTabs = tabs.value.slice();
      nextTabs[tabIndex].selected = option;
      const selectBack = tabIndex < nextTabs.length - 1;
      if (selectBack) {
        nextTabs = nextTabs.slice(0, tabIndex + 1);
      }
      const isLast = isLastOption(option);
      if (!isLast) {
        const nextTab = {
          options: option[mergedFieldKeys.value.children],
          selected: null
        };
        nextTabs.push(nextTab);
      }
      tabsCurrent.value = isLast ? tabIndex : nextTabs.length - 1;
      tempValue = option[mergedFieldKeys.value.value];
      tabs.value = nextTabs;
      emit("select", option, tabIndex);
      if (isLast || props.changeOnSelect) {
        const nextValue = option[mergedFieldKeys.value.value];
        innerValue.value = nextValue;
        const selectedOptions = nextTabs.map((tab) => tab.selected).filter(Boolean);
        emit("update:model-value", nextValue, selectedOptions);
        emit("change", nextValue, selectedOptions);
      }
    };
    const innerPaceholder = computed(() => {
      return props.hintText || t("pleaseSelect");
    });
    const mergedFieldKeys = computed(() => {
      return Object.assign(
        {},
        defaultFieldKeys,
        props.fieldKeys
      );
    });
    const innerValue = ref(props.modelValue);
    let tempValue = innerValue.value;
    const tabsCurrent = ref(0);
    const renderedPane = ref(false);
    const tabs = ref([]);
    const tabsList = computed(() => {
      return tabs.value.map((tab) => {
        const { selected } = tab;
        const tabLabel = selected ? selected[mergedFieldKeys.value.label] : innerPaceholder.value;
        return {
          title: tabLabel
        };
      });
    });
    watch(
      () => props.modelValue,
      () => {
        innerValue.value = props.modelValue;
        if (!isEmptyBinding(props.modelValue)) {
          if (tabs.value.some(
            (tab) => tab.selected?.[mergedFieldKeys.value.value] === props.modelValue
          )) {
            return;
          }
        }
        tempValue = props.modelValue;
        updateTabs();
      }
    );
    watch(
      () => props.options,
      () => {
        updateTabs();
      },
      {
        immediate: true
      }
    );
    const cascaderClass = computed(() => {
      return classNames(bem.b(), props.rootClass);
    });
    const cascaderStyle = computed(() => {
      return stringifyStyle(props.rootStyle);
    });
    const __returned__ = { props, emit, bem, t, updateTabs, isLastOption, onOptionClick, innerPaceholder, mergedFieldKeys, innerValue, get tempValue() {
      return tempValue;
    }, set tempValue(v) {
      tempValue = v;
    }, tabsCurrent, renderedPane, tabs, tabsList, cascaderClass, cascaderStyle, get classNames() {
      return classNames;
    }, get stringifyStyle() {
      return stringifyStyle;
    }, SarTabs, SarIcon, SarLoading };
    return __returned__;
  }
});
</script>

<style lang="scss">
@import './index.scss';
</style>